home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / Weather / Weather.app / Storm.m < prev    next >
Text File  |  1992-07-29  |  13KB  |  594 lines

  1. /*
  2.  * Object to peck on a remote network weather service.
  3.  *
  4.  * Michael Hawley
  5.  * MIT Media Laboratory
  6.  * 20 Ames Street
  7.  * Cambridge, MA 02139
  8.  * mike@media-lab.mit.edu
  9.  * Copyright (c) 1991 MIT Media Laboratory
  10.  * Burn before reading!  This means you!!
  11.  *
  12.  * Please forward any comments/revisions.
  13.  * Keep in mind that this was a one-day knock off;
  14.  * much of the complexity is due to the fact that
  15.  * we have to parse a telnet conversation that was
  16.  * never intended for such.
  17.  */
  18.  
  19. #import "Storm.h"
  20. #import "Process.h"
  21. #import <appkit/Form.h>
  22. #import <appkit/Font.h>
  23. #import <appkit/Text.h>
  24. #import <appkit/TextField.h>
  25. #import <appkit/Button.h>
  26. #import <appkit/PopUpList.h>
  27. #import <appkit/ScrollView.h>
  28. #import <appkit/Matrix.h>
  29. #import <appkit/NXBrowser.h>
  30. #import <appkit/Speaker.h>
  31. #import <appkit/Listener.h>
  32. #import "MyMenuCell.h"
  33. #import "Defaults.h"
  34. #import "License.h"
  35.  
  36. @implementation Storm
  37.  
  38. static int blank(char *s){
  39.     while (*s && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')) s++;
  40.     return *s? 0 : 1;
  41. }
  42.  
  43. int StormDebug = 1;
  44. id _status;
  45. extern int Verbose;
  46.  
  47. char *
  48. path(char *s)
  49. /*
  50.  * if 's' is in [NXArgv[0]], return [NXArgv[0]]/s.
  51.  * (for looking up internal commands and files in .../Opener.app/...).
  52.  */
  53. {
  54.     char t[1024], *q, *r;
  55.     static char p[1024];
  56.     extern char **NXArgv;
  57.     *t = '\0';
  58.     sscanf(s,"%s",t);
  59.     if (!*t || *t=='(') return s;
  60.     r = s + strlen(t);
  61.     strcpy(p,*NXArgv);
  62.     if (q=rindex(p,'/'))
  63.         strcpy(q+1,t);
  64.     else
  65.         strcpy(p,t);
  66.     if (access(p,0)==0){
  67.         strcpy(p+strlen(p),r);
  68.         return p;
  69.     }
  70.     return s;
  71. }
  72.  
  73. static void say(s, a,b,c,d) id s; char *a,*b,*c,*d; {
  74.     char p[1024];
  75.     sprintf(p,a,b,c,d);
  76.     [s setStringValue:p];
  77.     [s display];
  78.     NXPing();
  79. }
  80.  
  81. void message(a,b,c,d) char *a,*b,*c,*d; {
  82.     char p[1024];
  83.     sprintf(p,a,b,c,d);
  84.     [_status setStringValue:p];
  85.     [_status display];
  86.     NXPing();
  87. }
  88.  
  89. static int eq(char *a, char *b){ return strncmp(a,b,strlen(b))==0; }
  90. static int eqtail(char *s, char *t){ /* true if t appears at end of s */
  91.     int tn = strlen(t), sn = strlen(s);
  92.     if (tn > sn) return 0;
  93.     return strcmp(s+(sn-tn), t)==0;
  94. }
  95. static int streq(char *a, char *b){ return strcmp(a,b)==0; }
  96. static char *strindex(char *s, char *t){
  97.     int n = strlen(t);
  98.     if (s) while (*s)
  99.     if (!strncmp(s, t, n))
  100.         return s;
  101.     else
  102.         s++;
  103.     return (char *)0;
  104. }
  105. static int match(char *a, char *b){
  106.     return eq(a,b) || strindex(a,b) || strindex(b,a);
  107. }
  108. static char *stripnl(char *s){
  109.     char *p;
  110.     for (p=s;*p;p++) if (*p == '\n' || *p == '\r') *p = '\0';
  111.     return s;
  112. }
  113.  
  114. id _P;
  115.  
  116. static void put(P, fmt, a, b, c, d) id P; char *fmt, *a, *b, *c, *d; {
  117.     char p[1024];
  118.     sprintf(p,fmt,a,b,c,d);
  119.     if (Verbose) printf("+ %s\n",p);
  120.     [P puts:p]; 
  121. }
  122.  
  123. void Put(fmt, a, b, c, d) char *fmt, *a, *b, *c, *d; {
  124.     char p[1024];
  125.     sprintf(p,fmt,a,b,c,d);
  126.     if (Verbose) printf("+ %s\n",p);
  127.     if (_P) [_P puts:p]; 
  128. }
  129.  
  130.  
  131. static char *
  132. get(P, s, n) id P; char *s; int n; {
  133.     [P gets:s:n];
  134.     if (*s && Verbose) printf("> %s",s);
  135.     return *s? s : (char *)0; 
  136. }
  137.  
  138. char *
  139. pgets(s,n) char *s; int n; {
  140.     [_P gets:s:n];
  141.     return *s? s : (char *)0; 
  142. }
  143.  
  144. static char *
  145. flush(P,s) id P; char *s; {
  146.     static char t[1024];
  147.     while (get(P,t,sizeof t))
  148.         if (strindex(t,s)) return t;
  149.     sleep(1);
  150.     while (get(P,t,sizeof t))
  151.         if (strindex(t,s)) return t;
  152.     return (char *)0;
  153. }
  154.  
  155. char *
  156. Flush(s) char *s; {
  157.     static char t[1024];
  158.     if (_P) return;
  159.     while (get(_P,t,sizeof t))
  160.         if (strindex(t,s)) return t;
  161.     sleep(1);
  162.     while (get(_P,t,sizeof t))
  163.         if (strindex(t,s)) return t;
  164.     return (char *)0;
  165. }
  166.  
  167. - enable:(BOOL)b {
  168.     [attachB setIcon:b? "plug" : "unplug"];
  169.     return self;
  170. }
  171.  
  172. static id _text, _scroll;
  173.  
  174. - initMatrix {
  175.     // from the nib file, we have the help text; keep a pointer to it.
  176.     _text = helpText = [scrollView docView];
  177.     [_text setDelegate:self];
  178.     [_text setMarginLeft:6.0 right:6.0 top:0.0 bottom:0.0];
  179.     [_text notifyAncestorWhenFrameChanged:YES];
  180.     return self;
  181. }
  182.  
  183. - setScrollView:anObject {
  184.     _scroll = scrollView = anObject;
  185.     [self initMatrix];
  186.     return self;
  187. }
  188.  
  189. extern char DefaultFont[];
  190. extern char DefaultFontSize[];
  191. static id fid = (id)0;
  192. static int canconvert = 0;
  193. double atof();
  194.  
  195. - textWillConvert:textObject fromFont:from toFont:to {
  196.     if (canconvert && strcmp(DefaultFont,[from name])==0 &&
  197.     atof(DefaultFontSize) == [from pointSize]){
  198.     strcpy(DefaultFont,[to name]);
  199.     sprintf(DefaultFontSize,"%f",[to pointSize]);
  200.     fid = to;
  201.     writeDefaults();
  202.     }
  203.     return to;
  204. }
  205.  
  206. void
  207. setText(s) char *s; {
  208.     static NXPoint origin = {0.0,0.0};
  209.     id w = [_scroll window];
  210.  
  211.     if (!fid){
  212.         fid = [Font newFont:DefaultFont size:atof(DefaultFontSize)];
  213.     }
  214.     canconvert=0;
  215.     [w disableFlushWindow];
  216.     [_text setText:s];
  217.     [_text setSel:0:999999];
  218.     [_text setSelGray:0.0];
  219.     [_text setSelFont:fid];
  220.     [_text selectNull];
  221.     [_text scrollPoint:&origin];
  222.     [_scroll display];
  223.     [[w reenableFlushWindow] flushWindow];
  224.     NXPing();
  225.     canconvert=1;
  226. }
  227.  
  228. void openFile(char *s){ /* open 's' in workspace */
  229.     int ok = 0;
  230.     id p = [NXApp appSpeaker];
  231.     char t[512];
  232.  
  233.     sprintf(t,"\nThe file\n        %s\nwill open in the workspace.",s);
  234.     setText(t);
  235.     [p setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  236.     [p openFile:s ok:&ok];
  237.     if (!ok) sprintf(t,"\nCouldn't open: %s",s), setText(t);
  238. }
  239.  
  240. isRTF(s) char *s; {
  241.     int f = open(s,0);
  242.     if (f > 0){
  243.         char t[128];
  244.         int n = read(f,t,sizeof(t));
  245.         close(f);
  246.         if (n <= 0) return 0;
  247.         return strncmp(t,"{\\rtf",5)==0;
  248.     } else
  249.         return 0;
  250. }
  251.  
  252. void
  253. setFile(s) char *s; {
  254.     char *p = path(s);
  255.     NXStream *f = NXMapFile(p,NX_READONLY);
  256.     static NXPoint origin = {0.0,0.0};
  257.     id w = [_scroll window];
  258.  
  259.     canconvert=0;
  260.     if (!f) return ;
  261.     [w disableFlushWindow];
  262.  
  263.     if (isRTF(p)){
  264.     [_text setMonoFont:NO];
  265.     [_text readRichText:f];
  266.     } else {
  267.     [_text readText:f];
  268.         [_text setSel:0:999999];
  269.         [_text setSelGray:0.0];
  270.     if (!fid)
  271.         fid = [Font newFont:DefaultFont size:atof(DefaultFontSize)];
  272.         [_text setSelFont:fid];
  273.         [_text selectNull];
  274.         canconvert=1;
  275.     }
  276.     NXCloseMemory(f,NX_FREEBUFFER);
  277.     [_text scrollPoint:&origin];
  278.     [_scroll display];
  279.     [[w reenableFlushWindow] flushWindow];
  280. }
  281.  
  282. - showHelp:sender {
  283.     setFile("info");
  284.     return self;
  285. }
  286.  
  287. #define Case break; case
  288.  
  289. static char *prompt = "archie>";
  290.  
  291. squishRtn(char *s){
  292.     char *p = s;
  293.  
  294.     while (*p = *s++)
  295.         if (*p != '\r') ++p;
  296. }
  297.  
  298. static char *
  299. getLine(char *s, char *t){ /* read ...\n from s into t; return new s */
  300.     char *p = t;
  301.     *t = '\0';
  302.     squishRtn(s);
  303.     while (*s && *s != '\n') *p++ = *s++;
  304.     if (*s == '\n') *p++ = *s++;
  305.     *p++ = '\0';
  306.     if (*t == '\0') return (char *)0;
  307.     if (Verbose) printf("- %s",t);
  308.     return s;
  309. }
  310.  
  311. - processOutput:(char *)s {
  312.     static char prev[8192]="";
  313.     char t[1024], *p=prev;
  314.  
  315.     strcat(prev,s); s = t;
  316.     while ((p=getLine(p,s)) && 
  317.            (index(s,'\n') || strcmp(s+strlen(s)-2,": ")==0 ||
  318.                              strcmp(s+strlen(s)-1,":")==0))
  319.         execState(0,s);
  320.     strcpy(prev,blank(s)?s:"");
  321.     return self;
  322. }
  323.  
  324. static id me;
  325.  
  326. Command(s) char *s; {
  327.     if (!_P) {
  328.         substr(s,"$Site",Site);
  329.         _P = [Process new:s delegate:me];
  330.     }
  331. }
  332.  
  333. - click:sender {
  334.     id c =  [[browser matrixInColumn:[browser lastColumn]] selectedCell];
  335.     if ([c isLeaf])
  336.         [c click:self];
  337.     return self;
  338. }
  339.  
  340. - click2:sender {
  341.     return self;
  342. }
  343.  
  344. ensurelogin(){
  345.     [me ensurelogin];
  346.     return _P? 1 : 0;
  347. }
  348.  
  349. - ensurelogin {
  350.     //if (!_P) [self login:self];
  351.     return self;
  352. }
  353.  
  354. - login:sender {
  355.     if (_P) [_P free]; P = _P = (id)0;
  356.     _status = status;
  357.     [self setFetch];
  358.     ReadState(path("menus"));
  359.     [browser setDelegate:self];
  360.     [browser setCellPrototype:[[MyMenuCell alloc] init]];
  361.     [browser loadColumnZero];
  362.     [browser setAction:@selector(click:)];
  363.     [browser setDoubleAction:@selector(click2:)];
  364.     [browser setTarget:self];
  365.     [attachB setIcon:"plug"];
  366.     runState("");
  367.     return self;
  368. }
  369.  
  370. void
  371. logout(){
  372.     [me logout:me];
  373. }
  374.  
  375. - logout:sender {
  376.     if (P && _P) setState("Detach"), runState("");
  377.     if (P) [P terminate:self];
  378.     _P = P = (id)0;
  379.     [self enable:NO];
  380.     [attachB setIcon:"unplug"];
  381.     message("not connected.");
  382.     return self;
  383. }
  384.  
  385. extern int sleep();
  386.  
  387. - attach:sender {
  388.     if (eq((char *)[sender icon],"unplug")){
  389.         [self login:sender];
  390.     } else {
  391.         [self logout:sender];
  392.     }
  393.     return self;
  394. }
  395.  
  396. /*
  397.  * the buttons and commands to run at startup time.
  398.  */
  399. id Fetch[NumFetch];
  400.  
  401. int FetchSelected = -1;
  402.  
  403. - setFetch {
  404.     int i;
  405.     Fetch[0] = fetch1;
  406.     Fetch[1] = fetch2;
  407.     Fetch[2] = fetch3;
  408.     for (i=0;i<NumFetch;i++) [self setFetchText:i:FetchText[i]];
  409.     return self;
  410. }
  411.  
  412. - setFetchText:(int)i:(char *)s {
  413.     [Fetch[i] setStringValue:s];
  414.     strcpy(FetchText[i],s);
  415.     [Fetch[i] display];
  416.     return self;
  417. }
  418.  
  419. - setFetchText:(char *)s {
  420.     if (FetchSelected >= 0)
  421.         [self setFetchText:FetchSelected:s];
  422.     return self;
  423. }
  424.  
  425. void
  426. setFetchText(s) char *s; {
  427.     [me setFetchText:s];
  428. }
  429.  
  430. - setFetch:(int)i:(int)state {
  431.     [Fetch[i] setBackgroundGray:state?1.0:.666];
  432.     if (state) [self setFetchText:i:""];
  433.     else [Fetch[i] display];
  434.     return self;
  435. }
  436.  
  437. - hitRadio:sender {
  438.     int i;
  439.     int n = [sender selectedRow], state = [[sender selectedCell] state];
  440.     [self setFetch:n:state];
  441.     FetchSelected = state? n : -1;
  442.     for (i=0; i<NumFetch; i++){
  443.         if (i != n || !state){
  444.             [[sender cellAt:i:0] setState:0];
  445.             [self setFetch:i:0];
  446.         }
  447.     }
  448.     [sender display];
  449.     return self;
  450. }
  451.  
  452. fetchReports() {
  453.     int i;
  454.     char buf[80000], *p = buf;
  455.     while (pgets(buf,1024) && !strindex(buf,curMenuLast())) ;
  456.     *buf = '\0';
  457.     for (i=0;i<NumFetch;i++){
  458.        if (!blank(FetchText[i])){
  459.            message("%s. . .",FetchText[i]);
  460.            fetchReport(FetchText[i],p);
  461.            if (p[0]){
  462.                p += strlen(p);
  463.                if (i < (NumFetch-1))
  464.                    strcpy(p,"\n===============================\n");
  465.                p += strlen(p);
  466.            }
  467.        }
  468.     }
  469.     squishRtn(buf);
  470.     squishwhite(buf);
  471.     if (*buf) setText(buf);
  472.     message("connected!");
  473. }
  474.  
  475. - setSite:thing {
  476.     openDefaults();
  477.     site = thing;
  478.     [site setTitle:Site];
  479.     return self;
  480. }
  481.  
  482. - hitSite:sender {
  483.     char *s = (char *)[[sender selectedCell] title];
  484.     strcpy(Site,s);
  485.     writeDefaults();
  486.     return self;
  487. }
  488.  
  489. /*
  490.  * telnet:
  491.  */
  492. #import <appkit/Pasteboard.h>
  493. #import <appkit/Speaker.h>
  494. #import <appkit/Listener.h>
  495. - copyString:(char *)s {
  496.   id p = [Pasteboard new];
  497.   [p declareTypes:&NXAsciiPboard num:1 owner:self];
  498.   [p writeType:NXAsciiPboard data:s length:strlen(s)];
  499.   return self;
  500. }
  501.  
  502. - launchTerminal:(char *)program {
  503.   id p = [NXApp appSpeaker];
  504.   port_t t = NXPortFromName("Terminal",NULL);
  505.   int ok;
  506.   if (t==PORT_NULL) return self;
  507.   [p setSendPort:t];
  508.   [self copyString:program];
  509.   (void)[p msgPaste:&ok];
  510.   return self;
  511. }
  512.  
  513. - telnet:sender {
  514.     char p[1024];
  515.     sprintf(p,"telnet %s 3000\n",Site);
  516.     [self launchTerminal:p];
  517.     return self;
  518. }
  519.  
  520. - sendComments:sender {
  521.     return self;
  522. }
  523.  
  524. #import <appkit/PrintInfo.h>
  525.  
  526. - print:sender {
  527.     static int p = 0;
  528.     if (!p){
  529.         p++;
  530.         [[NXApp printInfo] setScalingFactor:.9];
  531.     }
  532.     return [_text printPSCode:sender];
  533. }
  534.  
  535. - pageLayout:sender {
  536.     return [NXApp runPageLayout:sender];
  537. }
  538.  
  539. + new {
  540.     me = self = [[Storm alloc] init];
  541.     return self;
  542. }
  543.  
  544. - free {
  545.     [self logout:self];
  546.     return [super free];
  547. }
  548.  
  549.  
  550. - appDidInit:sender {
  551.     openDefaults();
  552.     if (FirstUse()) [license show:self];
  553.     [attachB performClick:sender];
  554.     return self;
  555. }
  556.  
  557. - appWillTerminate:sender {
  558.     [self logout:self];
  559.     System("/bin/rm -rf /tmp/W_maps /tmp/W_scratch &");
  560.     writeDefaults();
  561.     return self;
  562. }
  563.  
  564. - (int)browser:sender fillMatrix:matrix inColumn:(int)column {
  565.     char *s = "Main";
  566.     if (column>0){
  567.         id c;
  568.         c = [[browser matrixInColumn:[browser lastColumn]] selectedCell];
  569.         s = [c get];
  570.     }
  571.     setMenu(s);
  572.     return numItem(s);
  573. }
  574.  
  575. - browser:sender loadCell:c atRow:(int)row inColumn:(int)column {
  576.     [c setStringValueNoCopy:curMenuItem(row)];
  577.     return self;
  578. }
  579.  
  580. - browserDidScroll:sender {
  581.     static int pc = -1;
  582.     int c = [browser firstVisibleColumn];
  583.     ensurelogin();
  584.     if (pc == c) return self;
  585.     pc = c;
  586.     if (c == 0) Put("m\n"), Flush("Change scroll"), setMenu("Main");
  587.     else
  588.     [[[browser matrixInColumn:0] selectedCell] click:self];
  589.     return self;
  590. }
  591.  
  592.  
  593. @end
  594.